﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RRRSRoguelike.Managers;
using RRRSRoguelike.Entities;
using System.Drawing;
using System.Threading;
using RRRSRoguelike.Helpers;
using RRRSRoguelike.Helpers.Actions;
using RRRSRoguelike.Helpers.Visualizer;
using RRRSRoguelikeData;
using System.IO;

namespace RRRSRoguelike.Screens
{
    /// <summary>
    /// Contains the main game logic
    /// </summary>
    class DungeonScreen:Screen
    {

        #region variables             
            public ActionManager ActionManager;
        
            //makes calls shorter
            private Player player;
            
            private bool hasJumped = false;
            private bool hasFired = false;
            
            private bool playerMoved;
            private bool processMonsters;
            
            private bool drawPanels = true;

        # endregion

        #region constructors
        
        public DungeonScreen()
        {



            ActionManager = new ActionManager();
            //Sets up the default keys
            ActionManager.SetDefaultKeys();

            SetupPanels();
        }


        #endregion

        #region methods

        private void MainGameLoop()
        {
            while (DungeonManager.Instance.IsGameActive)
            {
                
                //read input
                HandleInput();

                //do logic
                DoLogic();

                //Draw
                DoDraw();

            }
        }
        
        public void HandleInput()
        {
            GameManager.Instance.InputManager.ReadKeys();
        }

        public void DoLogic()
        {
            processMonsters = true;
            playerMoved = true;
            DungeonManager.Instance.Redraw = true;

            ProcessInput();

            //Can later be part of the prop manager perhaps or the fireball itself
            Fireball fireball = DungeonManager.Instance.PropManager.Fireball;
            if (fireball.Active)
                ProcessFireball(fireball);

            // does things like auto pick up sword and take stairs
            if (playerMoved)
                CheckNewTile();

            if (processMonsters)
            {
                DungeonManager.Instance.CreatureManager.ProcessMonsters();
            }
        }

        private void DoDraw()
        {
            if (drawPanels)
            {
                foreach (Panel p in Panels)
                    p.Draw();

                drawPanels = false;
            }
            DisplayHUD();

            DungeonManager.Instance.DrawDungeon();
        }
        
        private void StartGame(int seed = -1)
        {
            InitializeManagers(seed);

            LoadContent();
            TextScreen s = new TextScreen(DungeonManager.Instance.Texts["Welcome"]);
            s.Show();

            ResetBools();
            
            InitialDraw();

            //-----------------------------------------------------------------
            MainGameLoop();
            //-----------------------------------------------------------------

            ShowVictoryScreen();

            ReplayScreen rs = new ReplayScreen();
            rs.Show();
        }

        private void LoadContent()
        {
            DungeonManager.Instance.SoundManager.AddSound("Battle",
    Path.Combine(Properties.Settings.Default.CustomFolder, @"Sound\Battle.wav"));
            DungeonManager.Instance.Texts.Clear();
            DungeonManager.Instance.Texts.Add("GameOver",
                TxtFileToString.Read(Path.Combine(Properties.Settings.Default.CustomFolder, @"Texts\GameOver.txt")));
            DungeonManager.Instance.Texts.Add("Help",
                TxtFileToString.Read(Path.Combine(Properties.Settings.Default.CustomFolder, @"Texts\Help.txt")));
            DungeonManager.Instance.Texts.Add("Victory",
                TxtFileToString.Read(Path.Combine(Properties.Settings.Default.CustomFolder, @"Texts\Victory.txt")));
            DungeonManager.Instance.Texts.Add("Welcome",
                TxtFileToString.Read(Path.Combine(Properties.Settings.Default.CustomFolder, @"Texts\Welcome.txt")));
        }

        private void ProcessInput()
        {
            ActionManager ActionManager = GameManager.Instance.DungeonScreen.ActionManager;
            Player player = DungeonManager.Instance.CreatureManager.Player;

            //This checks until one is true as we can only have on action press.
            if (ActionManager.IsActionPushed(Actions.North))
                playerMoved = processMonsters = player.MovePlayer(Direction.N);
            else if (ActionManager.IsActionPushed(Actions.South))
                playerMoved = processMonsters = player.MovePlayer(Direction.S);
            else if (ActionManager.IsActionPushed(Actions.East))
                playerMoved = processMonsters = player.MovePlayer(Direction.E);
            else if (ActionManager.IsActionPushed(Actions.West))
                playerMoved = processMonsters = player.MovePlayer(Direction.W);
            else if (ActionManager.IsActionPushed(Actions.Jump) && !hasJumped)
            {
                DoJump();
            }
            else if (ActionManager.IsActionPushed(Actions.Shoot) && !hasFired)
            {
                ShootFireball();
            }
            else if (ActionManager.IsActionPushed(Actions.Pick))
            {
                ActionHelper.Get(player.Position);

                processMonsters = playerMoved = false;
            }
            else if (ActionManager.IsActionPushed(Actions.Drop))
            {
                ActionHelper.Put(player.Position);

                processMonsters = playerMoved = false;
            }
            else if (ActionManager.IsActionPushed(Actions.Look))
            {
                DoLook();

                processMonsters = playerMoved = false;
            }
            else if (ActionManager.IsActionPushed(Actions.Wait))
            {
                playerMoved = false;
            }
            else if (ActionManager.IsActionPushed(Actions.Quit))
            {
                QuitScreen s = new QuitScreen();
                s.Show();

                DungeonManager.Instance.DungeonVisualizer.ForceFullVisualization(DungeonManager.Instance.DungeonLevel);

                processMonsters = playerMoved = false;
            }
            else if (ActionManager.IsActionPushed(Actions.Help))
            {
                TextScreen hs = new TextScreen(DungeonManager.Instance.Texts["Help"]);
                hs.Show();
                DungeonManager.Instance.DungeonVisualizer.ForceFullVisualization(DungeonManager.Instance.DungeonLevel);
                processMonsters = playerMoved = false;
            }
            else if (ActionManager.IsActionPushed(Actions.FollowToggle))
            {
                //Toggle sound
                if (Properties.Settings.Default.FollowToggle)
                    Properties.Settings.Default.FollowToggle = false;
                else
                {
                    Properties.Settings.Default.FollowToggle = true;
                }
                Properties.Settings.Default.Save();

                processMonsters = playerMoved = false;

            }
            else if (ActionManager.IsActionPushed(Actions.SoundToggle))
            {
                //Toggle sound
                if (Properties.Settings.Default.SoundToggle)
                    Properties.Settings.Default.SoundToggle = false;
                else
                {
                    Properties.Settings.Default.SoundToggle = true;
                    GameManager.Instance.SoundManager.PlaySound(SoundList.Pluck.ToString());
                }
                Properties.Settings.Default.Save();

                processMonsters = playerMoved = false;

            }
            else if (ActionManager.IsActionPushed(Actions.ChangeAnimationSpeed))
            {
                Properties.Settings.Default.AnimationSpeed -= 10;
                if (Properties.Settings.Default.AnimationSpeed < 10)
                    Properties.Settings.Default.AnimationSpeed = 100;

                Properties.Settings.Default.Save();

                GameManager.Instance.SoundManager.PlaySound(SoundList.Pluck.ToString());

                processMonsters = playerMoved = false;
            }
            else
            {
                processMonsters = playerMoved = DungeonManager.Instance.Redraw = false;
            }
        }

        private void DoJump()
        {
            bool jump = true;
            Panels[1].Write("Choose direction.");
            while (jump)
            {
                HandleInput();
                Direction direction = GetDirection();
                if (direction != Direction.Wait)
                {
                    playerMoved = processMonsters = player.MovePlayer(direction, Constants.JumpDistance);
                    jump = false;
                    hasJumped = true;
                }
                else if (ActionManager.IsActionPushed(Actions.Quit) || ActionManager.IsActionPushed(Actions.Jump))
                    jump = false;

            }
 
        }

        private Direction GetDirection()
        {
            Direction direction;

            if (ActionManager.IsActionPushed(Actions.North))
                direction = Direction.N;
            else if (ActionManager.IsActionPushed(Actions.South))
                direction = Direction.S;
            else if (ActionManager.IsActionPushed(Actions.East))
                direction = Direction.E;
            else if (ActionManager.IsActionPushed(Actions.West))
                direction = Direction.W;
            else
                direction = Direction.Wait;

            return direction;
        }

        private void InitializeManagers(int seed)
        {
            DungeonManager.Instance.Initialize(seed);
            player = DungeonManager.Instance.CreatureManager.Player;

            GameManager.Instance.GameTime.Restart();


        }

        private void SetupPanels()
        {
            Panels = new List<Panel>();
            Panels.Add(new Panel(new Point(4, 1), Visualizer.GetScreenWidth() - 9, 5));
            Panels.Add(new Panel(new Point(4, 27), Visualizer.GetScreenWidth() - 9, 5));
            //Panels.Add (new Panel(new Point(4, 7), 20, Constants.DungeonHeight + 2));
            //Panels.Add ( new Panel(new Point(46, 7), 20, Constants.DungeonHeight + 2));
        }

        private void ResetBools()
        {
            hasJumped = false;
            hasFired = false;
        }

        private void InitialDraw()
        {
            //Swapping these two lines around stopped the flicker, no idea why!
            //this draws the panels
            DungeonManager.Instance.DungeonVisualizer.ForceFullVisualization(DungeonManager.Instance.DungeonLevel);
            //this does what it says on the tin. 
            DungeonManager.Instance.ForceRedraw();
            DrawTitle();
        }

        private void DrawTitle()
        {
            Panels[0].Clear();
            //removed seed
            Panels[0].Write(DungeonManager.Instance.DungeonLevel.ToString(), ConsoleColor.White, TextAlignment.Center); 
                //+ "  Seed: " + DungeonManager.Instance.Seed.ToString());
        }

        private static void ShowVictoryScreen()
        {
            TextScreen ts;
            if (DungeonManager.Instance.PlayerHasWon.Value)
            { ts = new TextScreen(DungeonManager.Instance.Texts["Victory"]); }
            else
            { ts = new TextScreen(DungeonManager.Instance.Texts["GameOver"]); }

            ts.Show();
        }

        public void ReDraw()
        {
            drawPanels = true;
            DrawTitle();
            DoDraw();
        }

        public override void Show()
        {
            Show(-1);
            base.Show();
        }

        public void Show(int seed = -1)
        {

            Console.Clear();
            drawPanels = true;


            
            StartGame(seed);
            MainGameLoop();

            base.Show();
        }



        private void DisplayHUD()
        {
            if (DungeonManager.Instance.CreatureManager.Player.Inventory.Any<Sword>())
            {
                StringBuilder sb = new StringBuilder("Sword: ");

                for (int i = 0; i < DungeonManager.Instance.CreatureManager.Player.Inventory.OfType<Sword>().First().UsesRemaining; i++)
                {
                    sb.Append("*");
                }

                Panels[1].Write(sb.ToString(), ConsoleColor.White,TextAlignment.Center);

            }
            else
            {
                Panels[1].Clear();
            }

        }

        private void CheckNewTile()
        {
            Point newPosition = new Point(player.X, player.Y);

            //Fight monster if there is one
            if (DungeonManager.Instance.CreatureManager.CreatureCollisions())
            {
                DungeonManager.Instance.Redraw = true;
            }

            //auto pick up sword
            ActionHelper.Get(newPosition);

            // auto take stairwell
            TakeStairWell(newPosition);
        }
        
        private void TakeStairWell(Point newPosition)
        {
            if (DungeonManager.Instance.DungeonLevel.GetTile(newPosition,Layers.Prop) is Stairwell)
            {
                //check for victory
                if (DungeonManager.Instance.CurrentDungeonLevel >= 5)
                {
                    DungeonManager.Instance.gameOver = true;
                }
                else
                {
                    MoveToNextLevel();
                }
            }
        }

        private void MoveToNextLevel()
        {
            hasJumped = false;
            hasFired = false;

            //no sword on next level. Murha, ha, ha, ha!!!
            //player.Inventory.Clear();
            //sword now has three uses

            DungeonManager.Instance.CurrentDungeonLevel++;
            DungeonManager.Instance.Dungeon.Levels.Add(new DungeonLevel(DungeonManager.Instance.CurrentDungeonLevel, Constants.DungeonWidth, Constants.DungeonHeight));
            DungeonManager.Instance.DungeonLevel.CreateRandomDungeonObjects();
            processMonsters = false;
            GameManager.Instance.DungeonScreen.ReDraw();
        }

        private void DoLook()
        {
            bool newTile = false;
            bool look = true;
            Tile lookTile = DungeonManager.Instance.PropManager.LookTile;
            lookTile.Active = true; 
            lookTile.Position = player.Position;

            while(look)
            {
                HandleInput();

                if (ActionManager.IsActionPushed(Actions.North))
                {lookTile.Y -= 1;newTile = true;}
                else if (ActionManager.IsActionPushed(Actions.South))
                {lookTile.Y += 1;newTile = true;}
                else if (ActionManager.IsActionPushed(Actions.East))
                {lookTile.X += 1;newTile = true;}
                else if (ActionManager.IsActionPushed(Actions.West))
                {lookTile.X -= 1;newTile = true;}
                else if (ActionManager.IsActionPushed(Actions.Quit) || ActionManager.IsActionPushed(Actions.Look))
                    look = false;

                if (newTile)
                {
                    //limit

                    lookTile.Position = DungeonLevel.ClampToDungeon(lookTile.Position);

                    Tile viewTile = (Tile)DungeonManager.Instance.DungeonLevel.GetTopTile(lookTile.Position);
                    lookTile.ImageCharacter = viewTile.ImageCharacter;
                    lookTile.Color = ConsoleColor.Cyan;

                    string description = "A mystery object.";

                    if (viewTile.Description != null)
                        description = viewTile.Description;

                    Panels[1].Write(description, ConsoleColor.White, TextAlignment.Center);

                    DungeonManager.Instance.ForceRedraw();
                    newTile = false;
                }
            //Draw
            }
            lookTile.Active = false;
            DungeonManager.Instance.ForceRedraw();
        }

        private void ShootFireball()
        {
            bool shoot = true;
            Panels[1].Write("Choose direction.");
            while (shoot)
            {
                Direction direction;
                HandleInput();
                direction = GetDirection();
                if (direction != Direction.Wait)
                {
                    DungeonManager.Instance.PropManager.Fireball = new Fireball(player.Position, direction);
                    DungeonManager.Instance.PropManager.Fireball.Reset();
                    hasFired = true;
                    shoot = false;
                }
                else if (ActionManager.IsActionPushed(Actions.Quit) || ActionManager.IsActionPushed(Actions.Shoot))
                    shoot = false;
                
            }
        }
        
        private static void ProcessFireball(Fireball fireball)
        {
            while (fireball.Active && DungeonManager.Instance.DungeonLevel.IsOKToMove(fireball.Position))
            {
                fireball.range--;
                //Do fireball stuff
                //DungeonManager.Instance.PropManager.Fireball
                //Fireball move
                DungeonManager.Instance.PropManager.Fireball.Move(fireball.Position, fireball.Direction, 1);
                //Fireball kill monsters
                List<Monster> monstersInBattle = 
                    DungeonManager.Instance.CreatureManager.Monsters.Where(m => m.X == fireball.X && m.Y == fireball.Y).ToList();
                foreach (Monster m in monstersInBattle)
                {
                    fireball.Kill(m);

                    DungeonManager.Instance.PlaySound(SoundList.Battle);

                    fireball.ImageCharacter = "*";

                    DungeonManager.Instance.DungeonVisualizer.Flash(fireball);

                    fireball.ImageCharacter = "o";
                    fireball.Color = ConsoleColor.Magenta;
                    fireball.Active = false;
                }
                if (fireball.range == 0)
                    fireball.Active = false;

                //Draw
                DungeonManager.Instance.ForceRedraw();

            }
            DungeonManager.Instance.PropManager.Fireball.Active = false;
            DungeonManager.Instance.Redraw = true;
        }
        
        #endregion

    }
}
